﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace System.Web.Mvc
{
    /// <summary>
    /// Helpers para el manejo del ModelState en los controladores
    /// </summary>
    public static class ModelStateHelpers {

        public static void AddModelErrors(this ModelStateDictionary modelState, IEnumerable<ValidationRuleViolation> errors)
        {
            foreach (ValidationRuleViolation issue in errors)
            {
                modelState.AddModelError(issue.PropertyName, issue.ErrorMessage);
            }
        }

        /// <summary>
        /// Agrega un error al modelo dada una violación regla
        /// </summary>
        /// <param name="modelState"></param>
        /// <param name="prmObjViolacionRegla">Violación de regla</param>
        public static void AddModelError(this ModelStateDictionary modelState, ValidationRuleViolation prmObjViolacionRegla)
        {
            modelState.AddModelError(prmObjViolacionRegla.PropertyName, prmObjViolacionRegla.ErrorMessage);
        }

        /// <summary>
        /// Agrega un error al modelo dada una excepción
        /// </summary>
        /// <param name="modelState"></param>
        /// <param name="prmObjException">Excepción</param>
        public static void AddModelError(this ModelStateDictionary modelState, string prmStrMensaje)
        {
            ValidationRuleViolation violacionRegla = new ValidationRuleViolation(prmStrMensaje);
            modelState.AddModelError(violacionRegla.PropertyName, violacionRegla.ErrorMessage);
        }

        /// <summary>
        /// Agrega un error inesperado al modelo
        /// </summary>
        /// <param name="modelState"></param>
        public static void AddModelErrorUnexpected(this ModelStateDictionary modelState)
        {
            ValidationRuleViolation violacionRegla = new ValidationRuleViolation("Ocurrió un error inesperado.");
            modelState.AddModelError(violacionRegla.PropertyName, violacionRegla.ErrorMessage);
        }
    }

    /// <summary>
    /// Clase que representa una violación de una regla concerniente a una propiedad
    /// </summary>
    public class ValidationRuleViolation
    {

        public string ErrorMessage { get; private set; }
        public string PropertyName { get; private set; }

        /// <summary>
        /// Permite construír una violación de regla para una propiedad de un entity
        /// </summary>
        /// <param name="mensajeError">Mensaje con el detalle del error</param>
        /// <param name="nombrePropiedad">Debe ser el nombre de una propiedad de la entidad relacionada</param>
        public ValidationRuleViolation(string mensajeError, string nombrePropiedad)
        {
            ErrorMessage = mensajeError;
            PropertyName = nombrePropiedad;
        }

        /// <summary>
        /// Permite construír una violación de regla general
        /// </summary>
        /// <param name="mensajeError">Mensaje con el detalle del error</param>
        public ValidationRuleViolation(string mensajeError)
        {
            ErrorMessage = mensajeError;
            PropertyName = "";
        }
    }


    /// <summary>
    /// Clase de excepción que permite encapsular la validación de reglas de dominio
    /// </summary>
    public class ValidationRulesException : Exception
    {
        public IEnumerable<ValidationRuleViolation> ViolacionesReglas { get; set; }
        /// <summary>
        /// Construye una excepción de validación a partir de un mensaje y la propiedad relacionada
        /// </summary>
        /// <param name="mensaje"></param>
        /// <param name="propiedad"></param>
        public ValidationRulesException(IEnumerable<ValidationRuleViolation> ruleValidations)
            : base()
        {
            ViolacionesReglas = ruleValidations;
        }
    }
}
